package com.nokia.bpmn.provider.rest;

import com.seed.bpmn.engine.IBPMNRepositoryService;
import com.seed.bpmn.engine.common.util.ResultData;
import com.seed.bpmn.engine.common.util.JsonUtil;
import com.seed.bpmn.engine.common.util.Page;
import com.seed.bpmn.engine.dto.FlowDTO;
import com.seed.bpmn.engine.dto.NodeDTO;
import com.seed.bpmn.engine.dto.ProcessDefinitionDTO;
import com.fasterxml.jackson.core.type.TypeReference;
import org.springframework.stereotype.Component;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * <p>流程模版相关服务接口</p>
 *
 * @author cscz89@126.com
 */
@Component("bpmnRepositoryService")
public class BpmnRepositoryServiceImpl extends BaseService implements IBPMNRepositoryService {

    private static String BASE_REPOSITORY_URL = BASE_URL + "/repository";

    @Override
    public ProcessDefinitionDTO deploy(String name, String fileName, String category,InputStream inputStream) throws Exception {
        String url = BASE_REPOSITORY_URL + "/deploy";
        LOGGER.info("部署（发布）流程模版（新增流程模版）:name={},fileName={},fileName={}", name, fileName, category);
        return post(
                new TypeReference<ResultData<ProcessDefinitionDTO>>() {},
                new ArrayList<Param>() {{
                    add(new Param("file", inputStream));
                    add(new Param("name", name));
                    add(new Param("fileName", fileName));
                    add(new Param("category", category));
                }}, url, null);
    }

    @Override
    public ProcessDefinitionDTO getProcessDefinition(String id) throws Exception {
        String url = BASE_REPOSITORY_URL + "/process-definition-id/{0}";
        LOGGER.info("通过流程定义id获取流程定义:id={}", id);
        return get(new TypeReference<ResultData<ProcessDefinitionDTO>>() {},url, id);
    }

    @Override
    public ProcessDefinitionDTO findProcessDefinitionByKey(String key) throws Exception {
        String url = BASE_REPOSITORY_URL + "/process-definition-key/{0}";
        LOGGER.info("通过流程定义key获取流程定义信息:key={}", key);
        return get(new TypeReference<ResultData<ProcessDefinitionDTO>>() {
        }, url, key);
    }

    @Override
    public NodeDTO getNodeByProcessDefinitionKey(String processDefinitionKey,String nodeId) throws Exception {
        String url = BASE_REPOSITORY_URL + "/node/process-definition-key";
        LOGGER.info("通过流程模版key获取最新流程模版中指定流程环节配置:processDefinitionKey={},nodeId={}",
            processDefinitionKey, nodeId);
        return post( new TypeReference<ResultData<NodeDTO>>(){},
                new ArrayList<Param>(){{
                    add(new Param("key", processDefinitionKey));
                    add(new Param("nodeId", nodeId));
                }},url, null);
    }

    @Override
    public List<NodeDTO> getNodeByProcessDefinitionId(String processDefinitionId) throws Exception {
        String url = BASE_REPOSITORY_URL + "/node/{0}";
        LOGGER.info("通过流程模版ID获取流程所有环节配置:processDefinitionId={}", processDefinitionId);
        return get(new TypeReference<ResultData<List<NodeDTO>>>() {}, url, processDefinitionId);
    }

    @Override
    public NodeDTO getNodeByProcessDefinitionId(String processDefinitionId,
                                                String nodeId) throws Exception {
        String url = BASE_REPOSITORY_URL + "/node/process-definition-id/{0}/{1}";
        LOGGER.info("通过流程模版id获取最新流程模版中指定流程环节配置:processDefinitionId={},nodeId={}",
            processDefinitionId, nodeId);
        return get(new TypeReference<ResultData<NodeDTO>>() {}, url, processDefinitionId, nodeId);
    }

    @Override
    public NodeDTO getNodeByTaskId(String taskId) throws Exception {
        String url = BASE_REPOSITORY_URL + "/node/task/{0}";
        LOGGER.info("获取任务所在流程环节配置:taskId={}", taskId);
        return get(new TypeReference<ResultData<NodeDTO>>() {}, url, taskId);
    }

    @Override
    public List<FlowDTO> getNextTransitions(String processDefinitionId,
                                            String taskId) throws Exception {
        String url = BASE_REPOSITORY_URL + "/next/transitions";
        url += "?processDefinitionId=" + processDefinitionId + "&taskId=" + taskId;
        LOGGER.info("获取下一流转线信息:processDefinitionId={},taskId={}", processDefinitionId, taskId);
        return get(new TypeReference<ResultData<List<FlowDTO>>>() {}, url);
    }

    @Override
    public List<FlowDTO> getNextTransitions(String processDefinitionId, String taskId, String nodeId) throws Exception {
        String url = BASE_REPOSITORY_URL + "/next/transitions";
        url += "?processDefinitionId=" + processDefinitionId + "&taskId=" + taskId + "&nodeId=" + nodeId;
        LOGGER.info("获取下一流转线信息:processDefinitionId={},taskId={},nodeId={}", processDefinitionId, taskId);
        return get(new TypeReference<ResultData<List<FlowDTO>>>() {}, url);
    }

    @Override
    public InputStream getProcessDefinitionXml(String processDefinitionId) throws Exception {
        return null;
    }

    @Override
    public InputStream getProcessDefinitionImage(String processDefinitionId) throws Exception {
        return null;
    }

    @Override
    public InputStream getProcessDefinitionById(String processDefinitionId, String type) throws Exception {
        String url = BASE_REPOSITORY_URL + "/resource/process-definition/{0}/type/{1}";
        LOGGER.info("获取流程定义（模版）资源:processDefinitionId={},type={}", processDefinitionId, type);
        byte[] bytes = get(byte[].class, url, processDefinitionId, type);
        return new ByteArrayInputStream(bytes);
    }

    @Override
    public InputStream getProcessDefinitionByProcessInstanceId(String processInstanceId,
                                                               String type) throws Exception {
        String url = BASE_REPOSITORY_URL + "/resource/process-instance/{0}/type/{1}";
        LOGGER.info("获取流程定义（模版）资源:processInstanceId={},type={}", processInstanceId, type);
        byte[] bytes = get(byte[].class, url, processInstanceId, type);
        return new ByteArrayInputStream(bytes);
    }

    @Override
    public void deleteProcessDefinition(List<String> ids) throws Exception {

    }

    @Override
    public void updateProcessDefinition(List<String> ids, int type) throws Exception {

    }

    @Override
    public List<Map<String, Object>> traceProcess(String processInstanceId) throws Exception {
        return null;
    }

    @Override
    public List<ProcessDefinitionDTO> findProcessDefinitionByPage(String name, String key, Page page) throws Exception {
        String url = BASE_REPOSITORY_URL + "/process-definition/page";
        Map<String, Object> result = post(new TypeReference<ResultData<Map<String, Object>>>() {
        }, new ArrayList<Param>() {
            {
                add(new Param("name", name));
                add(new Param("key", key));
                add(new Param("pageSize", page.getPageSize() + ""));
                add(new Param("pageIndex", page.getPageIndex() + ""));
            }
        }, url, null);
        page.setTotalObjects(Integer.parseInt(
            result.get("totalPages") == null ? "0" : result.get("totalPages").toString()));
        page.setPageIndex(Integer
            .parseInt(result.get("pageIndex") == null ? "0" : result.get("pageIndex").toString()));
        page.setTotalObjects(Integer.parseInt(
            result.get("totalObjects") == null ? "0" : result.get("totalObjects").toString()));
        Object items = result.get("items");
        return JsonUtil.parse(JsonUtil.toJson(items), new TypeReference<List<ProcessDefinitionDTO>>() {});
    }
}
